﻿using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;

using ButtonBuilder.Plugin;

using WPFColorPickerLib;
using WPFFontPickerLib;

namespace ButtonBuilder.Controls
{
    /// <summary>
    /// Interaction logic for ActionButton.xaml
    /// </summary>
    public partial class ActionButton : Button
    {
        private static readonly string DEFAULT_CAPTION = "New Action Button";

        #region Constructors
        /// <summary>
        /// Default constructor
        /// </summary>
        public ActionButton() : base()
        {
            InitializeComponent();

            Caption = DEFAULT_CAPTION;
            ButtonImageBackground.Background = new ImageBrush(new BitmapImage(
                new Uri("pack://application:,,,/ButtonBuilder;component/Images/button_default.png")));
        }

        #endregion

        #region Properties
        public override Border Border { get { return ButtonBorder; } }
        #endregion

        #region Methods
        private void PreparePluginsMenu()
        {
            //Remove all actions except the built-in plugin actions
            mnuActions.Items.Clear();
            mnuActions.Items.Add(mnuGotoPage);
            mnuActions.Items.Add(new Separator());

            foreach (var plugin in ParentWindow.Plugins.OrderByDescending(p => p.Description))
            {
                var pluginMenuItem = new MenuItem()
                {
                    Header = plugin.Description,
                    Tag = plugin
                };

                if (ClickAction.Name.Equals(pluginMenuItem.Header))
                {
                    pluginMenuItem.IsChecked = true;
                }

                pluginMenuItem.Click += new RoutedEventHandler(itmPluginMenuItem_Click);
                mnuActions.Items.Add(pluginMenuItem);
            }
        }

        private void PrepareGotoPageMenu()
        {
            mnuGotoPage.IsChecked = false;
            mnuGotoPage.Items.Clear();

            var gotoNewPageItem = new MenuItem()
            {
                Name = "itmGotoNewPage",
                Header = "New Page..."
            };

            gotoNewPageItem.Click += new RoutedEventHandler(itmGotoNewPage_Click);

            mnuGotoPage.Items.Add(gotoNewPageItem);
            mnuGotoPage.Items.Add(new Separator());

            foreach (var pageName in ParentWindow.GetPageNames())
            {
                if (pageName.Equals(Page.Name))
                    continue;

                var item = new MenuItem()
                {
                    Header = pageName
                };

                if ((ClickAction is Plugin.GotoPageAction) &&
                    (ClickAction as Plugin.GotoPageAction).GetParam("Page") == pageName)
                {
                    item.IsChecked = true;
                    mnuGotoPage.IsChecked = true;
                }

                item.Click += new RoutedEventHandler(HandleGotoPageMenu);

                mnuGotoPage.Items.Add(item);
            }
        }
        #endregion

        #region Overrides
        public override Data.Button GetData()
        {
            Data.Button data = base.GetData();

            if (CaptionAdorner != null)
            {
                data.Font = new Data.ButtonFont()
                {
                    Name = CaptionAdorner.CaptionControl.FontFamily.Source,
                    Size = CaptionAdorner.CaptionControl.FontSize,
                    Weight = CaptionAdorner.CaptionControl.FontWeight.ToOpenTypeWeight(),
                    Color = CaptionAdorner.CaptionControl.Foreground.ToString()
                };
            }

            if (ButtonImageBackground.Background as ImageBrush != null)
            {
                data.ImageVisible = true;
                data.ImagePath = ((ImageBrush)ButtonImageBackground.Background).ImageSource.ToString();
            }
            else if (ButtonImageBackground.Background as SolidColorBrush != null)
            {
                data.Background = ButtonImageBackground.Background.ToString();
            }

            return data;
        }

        public override void SetData(Data.Button data)
        {
            base.SetData(data);

            //NOTE: Font applied when CaptionAdorner is created.

            if (data.ImageVisible)
            {
                ButtonImageBackground.Background = new ImageBrush(new BitmapImage(new Uri(data.ImagePath)));
            }
            else
            {
                ButtonImageBackground.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString(data.Background));
            }
        }

        protected override void ApplyPressedTheme(bool pressed)
        {
            base.ApplyPressedTheme(pressed);

            ButtonBorder.BorderThickness = new Thickness(ButtonBorder.BorderThickness.Top +
                (pressed ? 1 : -1)); ;
        }

        protected override void OnPressDownTimerTick()
        {
            base.OnPressDownTimerTick();

            PreparePluginsMenu();
            PrepareGotoPageMenu();
        }
        #endregion

        #region ContextMenu Handlers
        private void itmRemove_Click(object sender, RoutedEventArgs e)
        {
            Dispatcher.BeginInvoke(new System.Threading.ThreadStart(() =>
            {
                ParentWindow.RemovePageButton(this);
            }));
        }

        private void itmCaptionText_Click(object sender, RoutedEventArgs e)
        {
            string userText = InputDialog.ShowDialog(ParentWindow, "Caption:", "Edit Caption",
                 CaptionAdorner.CaptionControl.Text, true);

            if (!string.IsNullOrWhiteSpace(userText))
            {
                Caption = userText;
                CaptionAdorner.Text = userText;
                AdornerLayer.GetAdornerLayer(ActionPanel).Update();

                OnPropertyChanged("Caption");
            }
        }

        private void itmCaptionFont_Click(object sender, RoutedEventArgs e)
        {
            FontChooser fontChooser = new FontChooser();
            fontChooser.Owner = Window.GetWindow(this);

            fontChooser.SetPropertiesFromObject(CaptionAdorner.CaptionControl);
            fontChooser.PreviewSampleText = CaptionAdorner.CaptionControl.Text;

            if (fontChooser.ShowDialog().Value)
            {
                fontChooser.ApplyPropertiesToObject(CaptionAdorner.CaptionControl);
                AdornerLayer.GetAdornerLayer(ActionPanel).Update();

                OnPropertyChanged("Font");
            }
        }

        private void itmCaptionColor_Click(object sender, RoutedEventArgs e)
        {
            ColorDialog colorDialog = new ColorDialog();
            colorDialog.Owner = Window.GetWindow(this);

            if ((bool)colorDialog.ShowDialog())
            {
                CaptionAdorner.CaptionControl.Foreground = new SolidColorBrush(colorDialog.SelectedColor);
                
                OnPropertyChanged("CaptionColor");
            }
        }

        private void itmGotoNewPage_Click(object sender, RoutedEventArgs e)
        {
            string pageName = null;
            string prompt = "New page name:";

            do
            {
                pageName = InputDialog.ShowDialog(ParentWindow, prompt, "Goto New Page");

                if (!string.IsNullOrWhiteSpace(pageName) && 
                    ParentWindow.GetPageNames().SingleOrDefault(p => p == pageName) == null)
                {
                    ClickAction = new Plugin.GotoPageAction(pageName);
                    ParentWindow.LoadPage(new Controls.Page(pageName));

                    OnPropertyChanged("ClickAction");
                    break;
                }
                else
                {
                    prompt = "Page already exists. New page name:";
                }
            } while (pageName != null);
        }

        private void itmPluginMenuItem_Click(object sender, RoutedEventArgs e)
        {
            MenuItem item = sender as MenuItem;

            if (!item.IsChecked)
            {
                item.IsChecked = true;

                PluginInfo pi = item.Tag as PluginInfo;
                IPlugin plugin = (IPlugin)PluginUtils.CreatePlugin(pi);
                plugin.Init();

                ClickAction = plugin;
                OnPropertyChanged("ClickAction");
            }
            
            if (ClickAction.Parameters.Count > 0 && PluginSettingsDialog.ShowDialog(ParentWindow, ClickAction))
            {
                OnPropertyChanged("ClickAction");
            }
        }

        private void HandleGotoPageMenu(object sender, RoutedEventArgs e)
        {
            MenuItem item = sender as MenuItem;
            item.IsChecked = true;

            ClickAction = new Plugin.GotoPageAction(item.Header.ToString());

            OnPropertyChanged("ClickAction");
        }

        private void ActionButton_ContextMenuOpening(object sender, ContextMenuEventArgs e)
        {
            PreparePluginsMenu();
            PrepareGotoPageMenu();
        }

        private void itmBackgroundPicture_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
            dlg.DefaultExt = ".png";
            dlg.Filter = "Image (.png)|*.png";

            if (dlg.ShowDialog(Window.GetWindow(this)) == true)
            {
                string imagePath = dlg.FileName;
                ButtonImageBackground.Background = new ImageBrush(new BitmapImage(new Uri(imagePath)));
                OnPropertyChanged("Image");
            }
        }

        private void itmBackgroundColor_Click(object sender, RoutedEventArgs e)
        {
            ColorDialog colorDialog = new ColorDialog();
            colorDialog.Owner = Window.GetWindow(this);

            if ((bool)colorDialog.ShowDialog())
            {
                ButtonImageBackground.Background = new SolidColorBrush(colorDialog.SelectedColor);
                OnPropertyChanged("Background");
            }
        }

        private void itmLower_Click(object sender, RoutedEventArgs e)
        {
            Page.LowerButton(this);
            OnPropertyChanged("ZIndex");
        }

        private void itmRaise_Click(object sender, RoutedEventArgs e)
        {
            Page.RaiseButton(this);
            OnPropertyChanged("ZIndex");
        }
        #endregion

        #region Caption Helpers
        private void ActionPanel_Loaded(object sender, RoutedEventArgs e)
        {
            if (CaptionAdorner == null)
            {
                CaptionAdorner = new ButtonCaption(this, ActionPanel, Caption);

                if (Font != null)
                {
                    CaptionAdorner.CaptionControl.FontFamily = new FontFamily(Font.Name);
                    CaptionAdorner.CaptionControl.FontSize = Font.Size;
                    CaptionAdorner.CaptionControl.FontWeight = FontWeight.FromOpenTypeWeight(Font.Weight);
                    CaptionAdorner.CaptionControl.Foreground = new SolidColorBrush(
                        (Color)ColorConverter.ConvertFromString(Font.Color));
                }

                AdornerLayer.GetAdornerLayer(ActionPanel).Add(CaptionAdorner);
            }
        }
        #endregion

        #region Focus Helpers

        private void TextBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (EnterKeyDown)
                return;

            if (e.Key == Key.Enter)
            {
                EnterKeyDown = true;
                base.OnMouseLeftButtonDown(null);
            }
        }

        private void TextBox_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                EnterKeyDown = false;
                base.OnMouseLeftButtonUp(null);
            }
        }

        private void TextBox_GotFocus(object sender, RoutedEventArgs e)
        {
            OnGotFocus(new RoutedEventArgs(GotFocusEvent, this));
        }
        #endregion
    }
}
